import Axios, { AxiosInstance, AxiosRequestConfig } from 'axios'
import {
  PureHttpError,
  RequestMethods,
  PureHttpResponse,
  PureHttpRequestConfig,
  Result,
  ContentTypeEnum
} from './types.d'
import { loadEnv } from '@build/index'
import NProgress from '../progress'
import qs from 'qs'
import { getCurrentInstance, h } from 'vue';
import { FrownOutlined } from '@ant-design/icons-vue';
import { notification } from 'ant-design-vue';
import router from "@/router";
import { isFunction } from '@/utils/is'
import { checkStatus } from './checkStatus'

import { TYPE, useToast } from 'vue-toastification'
const toast = useToast()

import { useLoginAccountStoreWithOut } from '@/store/modules/login'
import { DetectEnd, UA } from '../wecom'

const loginAccountStore = useLoginAccountStoreWithOut()

const { VITE_PROXY_DOMAIN, VITE_PROXY_DOMAIN_REAL, VITE_USE_MOCK, VITE_Redirect_Uri } = loadEnv()

const baseURL = VITE_USE_MOCK
  ? ''
  : process.env.NODE_ENV === 'production'
    ? VITE_PROXY_DOMAIN_REAL
    : VITE_PROXY_DOMAIN

const defaultConfig: AxiosRequestConfig = {
  baseURL: VITE_PROXY_DOMAIN_REAL,
  timeout: 10000000,
  headers: {
    Accept: 'application/json, text/plain, */*',
    'Content-Type': ContentTypeEnum.JSON,
    'X-Requested-With': 'XMLHttpRequest'
  },
  withCredentials: true,  
  paramsSerializer: params => qs.stringify(params, { indices: false })
}

const ua = DetectEnd();

class PureHttp {
  constructor() {
    this.httpInterceptorsRequest()
    this.httpInterceptorsResponse()
  }

  // Initialize the configuration object
  private static initConfig: PureHttpRequestConfig = {
    requestInterceptors: config => {
      // Enable progress bar animation
      NProgress.start()
      const loginStore = useLoginAccountStoreWithOut()
      const token = loginStore.getToken
      if (
        token &&
        //loginStore.checkExpireTime() &&
        !(config as Recordable).headers.Authorization
      ) {
        // jwt token
        ; (config as Recordable).headers.Authorization = token
      }
      return config
    },

    requestInterceptorsCatch: error => {
      return Promise.reject(error)
    },

    responseInterceptors: res => {
      // Turn off the progress bar animation
      NProgress.done()

      return res
    },

    responseInterceptorsCatch: (axiosInstance, error) => {
      const $error = error
      $error.isCancelRequest = Axios.isCancel($error)
      // Turn off the progress bar animation
      NProgress.done()

      checkStatus($error)

      return Promise.reject($error)
    }
  }
  // Save the current Axios instance object
  private static axiosInstance: AxiosInstance = Axios.create(defaultConfig)

  // Request interception
  private httpInterceptorsRequest(): void {
    PureHttp.axiosInstance.interceptors.request.use(
      (config: PureHttpRequestConfig) => {
        let token = loginAccountStore.getToken
        if (token !== null) {
          let bearer = `Bearer ${token}`;
          config.headers.Authorization = bearer          
        }
        let $config = config
        
        if (
          PureHttp.initConfig.requestInterceptors &&
          isFunction(PureHttp.initConfig.requestInterceptors)
        ) {
          $config = PureHttp.initConfig.requestInterceptors($config)
        }
        return $config
      },
      undefined
    )
    if (
      PureHttp.initConfig.requestInterceptorsCatch &&
      isFunction(PureHttp.initConfig.requestInterceptorsCatch)
    ) {
      PureHttp.axiosInstance.interceptors.request.use(
        undefined,
        PureHttp.initConfig.requestInterceptorsCatch
      )
    }
  }

  // Response interception
  private httpInterceptorsResponse(): void {
    PureHttp.axiosInstance.interceptors.response.use(
      (response: PureHttpResponse) => {
        if (
          PureHttp.initConfig.responseInterceptors &&
          isFunction(PureHttp.initConfig.responseInterceptors)
        ) {
          response = PureHttp.initConfig.responseInterceptors(response)
        }

        return response.data
      },
      (error: PureHttpError) => {
        let $error = error
        $error.isCancelRequest = Axios.isCancel($error)
        
        if (error.response?.status === 401) {
          if (ua !== UA.Browser && ua !== UA.BrowserApp) {
            let authUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=wwce43b50f723f7ec6&redirect_uri=${encodeURI(`${VITE_Redirect_Uri}/ams/api/wecom`)}&response_type=code&scope=snsapi_privateinfo&agentid=1000025#wechat_redirect`
            
            window.location.href = authUrl
          }
          else {        
            toast('登录失效，请重新登录', { timeout: 2000, type: TYPE.ERROR });
            
            console.log('http模块跳转login');            
            router.push('/login')
          }
        }

        if (error.response?.status === 403) {
          toast('当前登录用户的权限不足，请联系管理员', { timeout: 2000, type: TYPE.WARNING });          
        }
        
        return Promise.reject($error)
      }
    )

    if (
      PureHttp.initConfig.responseInterceptorsCatch &&
      isFunction(PureHttp.initConfig.responseInterceptorsCatch)
    ) {
      PureHttp.axiosInstance.interceptors.response.use(
        undefined,
        (error: PureHttpError) => {
          // @ts-ignore
          return PureHttp.initConfig.responseInterceptorsCatch(
            PureHttp.axiosInstance,
            error
          )
        }
      )
    }
  }

  public request<T = any>(
    method: RequestMethods,
    url: string,
    param?: AxiosRequestConfig,
    axiosConfig?: PureHttpRequestConfig
  ): Promise<Result<T>> {
    const config = {
      method,
      url,
      ...param,
      ...axiosConfig
    } as PureHttpRequestConfig

    // Handling custom request/response callbacks individually
    return new Promise((resolve, reject) => {
      PureHttp.axiosInstance
        .request<any, PureHttpResponse>(config)
        .then((response: PureHttpResponse) => {
          resolve(response as unknown as Promise<Result<T>>)
        })
        .catch(error => {
          reject(error)
        })
    })
  }

  // Separately extracted post tool function
  public post<T = any>(
    url: string,
    params?: any,
    config?: PureHttpRequestConfig
  ): Promise<Result<T>> {
    return this.request<T>('post', url, params, config)
  }

  // Separately extracted get utility function
  public get<T = any>(
    url: string,
    params?: any,
    config?: PureHttpRequestConfig
  ): Promise<Result<T>> {
    return this.request<T>('get', url, params, config)
  }
}

export const http = new PureHttp()
